// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: support test of communication of simple-client
// feature: DServer support simple entity
// feature: provide query interfaces
// feature: develop dispatcher
// feature: discovery support client and server
// ------------------------------------------------------------------

#ifndef _EDDS_RTPS_DISCOVERY_PARTICIPANT_INFO_H_
#define _EDDS_RTPS_DISCOVERY_PARTICIPANT_INFO_H_

#include <vector>

#include <history/CacheChange.h>
#include <edds/rtps/common/GuidPrefix_t.hpp>

#include <discovery/database/DiscoverySharedInfo.hpp>
#include <discovery/database/DiscoveryParticipantChangeData.hpp>

#include <nlohmann/json.hpp>

namespace evbs {
namespace ertps {
namespace rtps {
namespace ddb {

/**
 * Class to join the main info required from a Participant in the Discovery Data Base
 *@ingroup DISCOVERY_MODULE
 */
class DiscoveryParticipantInfo : public DiscoverySharedInfo {
 public:
    DiscoveryParticipantInfo() : DiscoverySharedInfo() {}
    DiscoveryParticipantInfo(CacheChange_t* change, const GuidPrefix_t& known_participant,
                             const DiscoveryParticipantChangeData& participant_change_data)
        : DiscoverySharedInfo(change, known_participant), participant_change_data_(participant_change_data) {}

    ~DiscoveryParticipantInfo() {}

    CacheChange_t* update(CacheChange_t* change, const DiscoveryParticipantChangeData& participant_change_data);

    CacheChange_t* update(CacheChange_t* change) { return DiscoverySharedInfo::update(change); }

    CacheChange_t* update_and_unmatch(CacheChange_t* change,
                                      const DiscoveryParticipantChangeData& participant_change_data);

    CacheChange_t* update_and_unmatch(CacheChange_t* change) { return DiscoverySharedInfo::update_and_unmatch(change); }

    // populate functions
    void add_reader(const GUID_t& guid);

    void remove_reader(const GUID_t& guid);

    void add_writer(const GUID_t& guid);

    void remove_writer(const GUID_t& guid);

    bool is_client() const { return participant_change_data_.is_client(); }

    bool is_superclient() const { return participant_change_data_.is_superclient(); }

    bool is_local() const { return participant_change_data_.is_local(); }

    bool is_simple() const { return participant_change_data_.is_simple(); }

    bool is_mvbs() const { return participant_change_data_.is_mvbs(); }

    bool is_compatible() const { return participant_change_data_.is_compatible(); }

    uint16_t domain_id() const { return participant_change_data_.domain_id(); }

    string_255 participant_name() const { return participant_change_data_.participant_name(); }
    std::string start_time() const { return participant_change_data_.start_time(); }
    TransportTypeKind transport_type() const { return participant_change_data_.transport_type(); }
    int64_t get_announce() const { return participant_change_data_.get_announce(); }
    Time_t announce() const { return participant_change_data_.announce(); }

    void participant_change_data(const DiscoveryParticipantChangeData& new_participant_change_data) {
        participant_change_data_ = new_participant_change_data;
    }

    bool is_external() const { return (!is_local()); }

    RemoteLocatorList metatraffic_locators() const { return participant_change_data_.metatraffic_locators(); }

    std::vector<GUID_t> readers() const { return readers_; }

    std::vector<GUID_t> writers() const { return writers_; }

    void to_json(nlohmann::json& j) const;
    void own_to_json(nlohmann::json& j, std::vector<SequenceNumber_t> sn_list) const;

 private:
    std::vector<GUID_t> readers_;

    std::vector<GUID_t> writers_;

    DiscoveryParticipantChangeData participant_change_data_;
};

inline std::ostream& operator<<(std::ostream& output, const DiscoveryParticipantInfo& part_info) {  //LCOV_EXCL_START
    output << "\n=================================================================\n";
    output << "is_client: " << (part_info.is_client() ? "True" : "False") << "\n";
    output << "is_superclient: " << (part_info.is_superclient() ? "True" : "False") << "\n";
    output << "is_local: " << (part_info.is_local() ? "True" : "False") << "\n";
    output << "is_simple: " << (part_info.is_simple() ? "True" : "False") << "\n";
    output << "is_mvbs: " << (part_info.is_mvbs() ? "True" : "False") << "\n";
    output << "is_compatible: " << (part_info.is_compatible() ? "True" : "False") << "\n";
    output << "domain_id: " << part_info.domain_id() << "\n";
    output << "participant_name: " << part_info.participant_name() << "\n";
    output << "start_time: " << part_info.start_time() << "\n";
    output << "announce: " << part_info.get_announce() << "ns \n";
    output << "metatraffic_locators: " << part_info.metatraffic_locators() << "\n";
    output << "[readers: ";
    if (!part_info.readers().empty()) {
        for (auto reader_guid : part_info.readers()) {
            output << reader_guid << ",";
        }
    } else {
        output << "_";
    }
    output << "]\n";
    output << "[writers: ";
    if (!part_info.writers().empty()) {
        for (auto writer_guid : part_info.writers()) {
            output << writer_guid << ",";
        }
    } else {
        output << "_";
    }
    output << "]\n";
    output << "----------------------------------------------------------------\n";
    return output;
}  //LCOV_EXCL_STOP

} /* namespace ddb */
} /* namespace rtps */
} /* namespace ertps */
} /* namespace evbs */

#endif /* _EDDS_RTPS_PARTICIPANT_INFO_H_ */
